import SpawnController from '@/modules/structures/spawn'
import { RemoteHarvestTask } from './types'
import { CreepRoles } from '@/modules/structures/spawn/types'
import { getCreepWarAbility, isEnemy } from '@/utils/war'
import { BodyPartArrayType } from '@/utils/common'
import { goTo } from '@/modules/move'
import { isInterval } from '@/ayaka'
import { getFreeSpace } from '@/utils/position'

/**
 * 孵化 remoteGuard
 */
export const spawnRemoteGuard = function (room: MyRoom, task: RemoteHarvestTask, enemys?: Creep[]) {
    if (task.remoteGuard.length) return
    if (SpawnController.searchSpawnTaskByRole(room, CreepRoles.remoteGuard).length) return

    let body: BodyPartArrayType | undefined = undefined
    if (!enemys) {
        const remoteRoom = Game.rooms[task.roomName]
        if (remoteRoom) enemys = remoteRoom.enemys || remoteRoom.find(FIND_HOSTILE_CREEPS).filter(isEnemy)
    }

    if (task.isCenterNine && !task.isCenter) {
        body = [
            [MOVE, 25],
            [ATTACK, 18],
            [HEAL, 7],
        ]
    } else if (enemys?.length) {
        body = getRemoteGuardBody(room, enemys)
    } else {
        const partNumber = Math.min(Math.floor(room.energyCapacityAvailable / 130), 25)
        body = [
            [MOVE, partNumber - 1],
            [ATTACK, partNumber],
            [MOVE, 1],
        ]
    }
    if (!body) {
        task.data.restartTime = Game.time + 1500
        delete task.data.isDanger
        return
    }

    const creepName = SpawnController.addSpawnTask(room, {
        role: CreepRoles.remoteGuard,
        body,
    })
    if (!creepName) return

    task.remoteGuard.push(creepName)
}

/**
 * 计算 remoteGuard 身体部件
 */
const getRemoteGuardBody = function (room: MyRoom, enemys: Creep[]) {
    // 先找最厉害的敌人
    enemys.forEach((e) => getCreepWarAbility(e))
    const enemy = _.max(enemys, (e) => e._warAbility.attack + e._warAbility.rangeAttack)
    if (!enemy) return

    // 先看看这个爬打得过吗，打不过就不打了
    const heal = Math.max(Math.ceil((enemy._warAbility.attack / 2 + enemy._warAbility.rangeAttack) / 10), 0) + 1
    const attack = Math.ceil((enemy._warAbility.heal * 2) / 30) + 5
    const tough = Math.max(Math.floor(enemy.body.length / 2) - heal - attack, 0)
    const move = heal + attack + tough

    if (heal + attack + tough + move > 50) return

    const energy = tough * 10 + move * 50 + attack * 80 + heal * 250
    if (room.energyCapacityAvailable < energy) return

    const body: BodyPartArrayType = []
    if (tough) body.push([TOUGH, tough] as any)
    if (move - 1) body.push([MOVE, move - 1] as any)
    if (attack) body.push([ATTACK, attack] as any)
    if (heal) body.push([HEAL, heal] as any)
    body.push([MOVE, 1] as any)

    return body
}

/**
 * 外矿守卫工作
 */
export const remoteGuardWork = function (creeps: Creep[], task: RemoteHarvestTask, remoteRoom?: Room) {
    creeps = creeps.filter((creep) => !creep.spawning)

    // 是否是九房但不是中心房
    const isNormalCenterNine = task.isCenterNine && !task.isCenter

    creeps.forEach((creep) => {
        if (creep.room.name !== task.roomName && creep.hits === creep.hitsMax) {
            goTo(creep, new RoomPosition(25, 25, task.roomName), { range: 23 })
            return
        }

        if (!remoteRoom) {
            if (creep.hits < creep.hitsMax) creep.heal(creep)
            return
        }

        const enemys = remoteRoom.find(FIND_HOSTILE_CREEPS).filter(isEnemy)
        if (!enemys.length) {
            if (task.data.isDanger) {
                task.data.duration = (task.data.duration || 1) - 1
                if (task.data.duration <= 0) {
                    delete task.data.isDanger
                    delete task.data.duration
                }
            }

            if (creep.hits < creep.hitsMax) {
                if (creep.getActiveBodyparts(HEAL)) {
                    creep.heal(creep)
                } else {
                    // 回家治疗
                    const myRoom = Game.rooms[creep.memory.belong] as MyRoom
                    const centerPos =
                        new RoomPosition(myRoom.memory.center[0], myRoom.memory.center[1], myRoom.name) ||
                        myRoom.controller.pos
                    if (creep.pos.getRangeTo(centerPos) > 3) {
                        goTo(creep, centerPos, { range: 3 })
                    }
                }
            }

            // 将可能出现的 invader_core 记入 sourceId 中
            if (isInterval(53) && !creep.memory.sourceId) {
                const enemyStructures = remoteRoom
                    .find(FIND_STRUCTURES)
                    .filter(
                        (s) =>
                            s.structureType === STRUCTURE_INVADER_CORE ||
                            (!s.my &&
                                (!remoteRoom.controller || s.pos.isNearTo(remoteRoom.controller)) &&
                                ['constructedWall', 'rampart'].includes(s.structureType)),
                    )

                const invaderCore = enemyStructures.find((s) => s.structureType === STRUCTURE_INVADER_CORE) as
                    | StructureInvaderCore
                    | undefined

                if (enemyStructures.length && !task.isCenterNine) {
                    creep.memory.sourceId = invaderCore?.id || enemyStructures[0].id
                }

                // 核心要塞
                if (
                    invaderCore &&
                    task.isCenterNine &&
                    (!invaderCore.ticksToDeploy || invaderCore.ticksToDeploy < 3000)
                ) {
                    const effectindex = invaderCore.effects.findIndex((e) => e.effect == EFFECT_COLLAPSE_TIMER)
                    if (effectindex > -1) {
                        task.data.restartTime = Game.time + invaderCore.effects[effectindex].ticksRemaining
                    } else {
                        const rampart = remoteRoom.find(FIND_STRUCTURES, {
                            filter: (s) => s.structureType === STRUCTURE_RAMPART,
                        })[0] as StructureRampart
                        if (rampart && rampart.ticksToDecay) {
                            task.data.restartTime = Game.time + rampart.ticksToDecay
                        } else {
                            task.data.restartTime = Game.time + 75000 * 1.1
                        }
                    }
                }
            }

            if (!creep.memory.targetId) {
                // 找受伤的爬
                const hurtCreep = remoteRoom
                    .find(FIND_CREEPS)
                    .filter((c) => c.hits < c.hitsMax && c.my && c.memory.role !== CreepRoles.remoteCarrier)[0]
                if (hurtCreep) {
                    if (!isNormalCenterNine || creep.pos.getRangeTo(hurtCreep) <= 7) {
                        creep.memory.targetId = hurtCreep.id
                    }
                }
            }

            if (creep.memory.targetId) {
                const target = Game.getObjectById(creep.memory.targetId as Id<Creep | StructureKeeperLair>)
                if (target && (target instanceof StructureKeeperLair || target.hits < target.hitsMax)) {
                    if (creep.pos.isNearTo(target)) {
                        target instanceof Creep && creep.heal(target)
                    } else {
                        goTo(creep, target.pos, { maxRooms: 1 })
                    }
                    return
                } else {
                    delete creep.memory.targetId
                }
            }

            if (creep.memory.sourceId) {
                const invaderCore = Game.getObjectById(creep.memory.sourceId as Id<StructureInvaderCore>)
                if (invaderCore) {
                    if (creep.pos.isNearTo(invaderCore)) {
                        creep.attack(invaderCore)
                    } else {
                        goTo(creep, invaderCore.pos, { maxRooms: 1 })
                    }
                    return
                } else {
                    delete creep.memory.sourceId
                }
            }

            if (!isNormalCenterNine) {
                // 驻守点位
                const range = 5
                const guardPos = remoteRoom.controller?.pos || new RoomPosition(25, 25, remoteRoom.name)
                if (creep.pos.getRangeTo(guardPos) > range) {
                    goTo(creep, guardPos, { range, maxRooms: 1 })
                }
                // 如果脚下是路，往周围不是路的位置走
                if (isInterval(19) && creep.pos.lookFor(LOOK_STRUCTURES).length) {
                    const freePos = getFreeSpace(creep.pos, { ignoreCreep: false })
                        .filter((pos) => (pos._dis = pos.getRangeTo(guardPos)) <= 5)
                        .sort((a, b) => a._dis - b._dis)
                    if (freePos.length) {
                        creep.move(creep.pos.getDirectionTo(freePos[0]))
                    }
                }
                return
            }

            // 找较近的要孵化的 keeperLairs，即距离+ticksToSpawn最小
            const keeperLairs = remoteRoom.find(FIND_HOSTILE_STRUCTURES, {
                filter: { structureType: STRUCTURE_KEEPER_LAIR },
            }) as StructureKeeperLair[]
            const closestKeeperLair = keeperLairs.sort(
                (a, b) =>
                    (a.ticksToSpawn || 0) +
                    creep.pos.getRangeTo(a) * 1.1 -
                    ((b.ticksToSpawn || 0) + creep.pos.getRangeTo(b) * 1.1),
            )[0]
            if (closestKeeperLair) {
                creep.memory.targetId = closestKeeperLair.id
            }
        } else {
            delete creep.memory.targetId
            task.data.isDanger = true
            task.data.duration = 20

            const enemy = creep.pos.findClosestByRange(enemys)
            if (!enemy) return

            const attack = creep.getActiveBodyparts(ATTACK)
            const range = creep.pos.getRangeTo(enemy)

            if (!attack) {
                goTo(creep, enemy.pos, { flee: true, maxRooms: 1 })
            } else if (range > 1) {
                // 血量充足才追
                if (creep.hits > creep.hitsMax * 0.8) {
                    creep.moveTo(enemy.pos, { maxRooms: 1 })
                }
            } else if (!enemy.fatigue) {
                creep.move(creep.pos.getDirectionTo(enemy.pos))
            }

            if (attack && range <= 1) {
                if (enemy.getActiveBodyparts(ATTACK) >= attack && creep.hits < creep.hitsMax) {
                    creep.heal(creep)
                } else {
                    creep.attack(enemy)
                }
            } else if (creep.hits < creep.hitsMax || range <= 3) {
                creep.heal(creep)
            }
        }
    })
}
